package com.youkeyi.ddy.cloud.common.utils;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.*;
import redis.clients.jedis.exceptions.JedisException;

import java.util.*;

/**
 * RedisUtils
 *
 * @Author liuxiawang
 * @Date 2021-03-12 22:24
 * @Location shenzhen.china
 */
public class RedisUtils {

    private static final String LOCK_SUCCESS = "OK";
    private static final Long RELEASE_SUCCESS = 1L;
    /** NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the key if it already exist. **/
    public static final String NOT_EXIST = "NX";
    public static final String EXIST = "XX";
    /** expx EX|PX, expire time units: EX = seconds; PX = milliseconds **/
    public static final String SECONDS = "EX";
    public static final String MILLISECONDS = "PX";

    /**
     * Jedis连接池
     */
    private static JedisPool jedisPool;
    /**
     * Jedis授权码
     */
    private static String authentication;

    /**
     * 获取Jedis客户端
     *
     * @return
     * @throws JedisException
     */
    private static Jedis getJedis() throws JedisException {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (null != jedis && StringUtils.isNotBlank(authentication)) {
                jedis.auth(authentication);
            }
        } catch (JedisException e) {
//			if (jedis != null) {
//				jedisPool.returnResourceObject(jedis);
//			}
            release(jedis, true);
            e.printStackTrace();
            throw e;
        }
        return jedis;
    }

    /**
     * 释放Jedis客户端资源
     *
     * @param jedis
     * @param isBroken
     */
    private static void release(Jedis jedis, boolean isBroken) {
        if (jedis != null) {
//			if (isBroken) {
//				jedisPool.returnBrokenResource(jedis);
//			} else {
//				jedisPool.returnResource(jedis);
//			}
            jedis.close();
        }
    }

    /**
     *
     * @Function: RedisUtils.java
     * @Description: 根据key模糊匹配删除
     *
     */
    public static Long delFuzzyKeys(Integer dbIndex, String key) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        long result = 0;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            List<String> keys = getKeys(dbIndex, key);
            for (String string : keys) {
                jedis.del(string);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return result;
    }

    /**
     * 保存字符串数据到Redis
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param value 数据值
     * @param cacheSeconds 缓存时间，0表示永久保存
     * @return 返回旧的数据值
     */
    public static String addStringToJedis(Integer dbIndex, String key, String value, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        String lastVal = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            lastVal = jedis.getSet(key, value);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return lastVal;
    }

    /**
     * 保存字符串数据到Redis（批量）
     *
     * @param dbIndex 数据库序号
     * @param batchData 保存的批量字符串数据
     * @param cacheSeconds 缓存时间，0表示永久保存
     */
    public static void addStringToJedis(Integer dbIndex, Map<String, String> batchData, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            Pipeline pipeline = jedis.pipelined();
            for (Map.Entry<String, String> element : batchData.entrySet()) {
                if (cacheSeconds != 0) {
                    pipeline.setex(element.getKey(), cacheSeconds, element.getValue());
                } else {
                    pipeline.set(element.getKey(), element.getValue());
                }
            }
            pipeline.sync();
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 保存字符串列表到Redis
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param list 字符串列表
     * @param cacheSeconds 缓存时间，0表示永久保存
     */
    public static void addListToJedis(Integer dbIndex, String key, List<String> list, int cacheSeconds) throws Exception {
        Exception exc = null;
        if (list != null && list.size() > 0) {
            Jedis jedis = null;
            boolean isBroken = false;
            try {
                jedis = getJedis();
                jedis.select(dbIndex);
                if (jedis.exists(key)) {
                    jedis.del(key);
                }
                for (String aList : list) {
                    jedis.rpush(key, aList);
                }
                if (cacheSeconds != 0) {
                    jedis.expire(key, cacheSeconds);
                }
            } catch (Exception e) {
                isBroken = true;
                exc = e;
            } finally {
                release(jedis, isBroken);
                if (exc != null) {
                    throw exc;
                }
            }
        }
    }

    /**
     * 保存字符串集合到Redis
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param value
     */
    public static void addToSetJedis(Integer dbIndex, String key, String[] value) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.sadd(key, value);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 移除Key对应集合里面的元素
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param value
     */
    public static void removeSetJedis(Integer dbIndex, String key, String value) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.srem(key, value);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 移除Key对应集合里面的元素(批量)
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param values
     */
    public static void removeSetJedis(Integer dbIndex, String key, List<String> values) throws Exception {
        if (CollectionUtils.isNotEmpty(values)) {
            Jedis jedis = null;
            boolean isBroken = false;
            Exception exc = null;
            try {
                jedis = getJedis();
                jedis.select(dbIndex);
                jedis.srem(key, values.toArray(new String[]{}));
            } catch (Exception e) {
                isBroken = true;
                exc = e;
            } finally {
                release(jedis, isBroken);
                if (exc != null) {
                    throw exc;
                }
            }
        }
    }

    /**
     * 向Key指向的队列压入数据
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param data 数据值
     * @param cacheSeconds 缓存时间，0表示永久保存
     */
    public static void pushDataToListJedis(Integer dbIndex, String key, String data, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.rpush(key, data);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 向Key指向的队列压入数据（批量）
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param batchData 批量数据值
     * @param cacheSeconds 缓存时间，0表示永久保存
     */
    public static void pushDataToListJedis(int dbIndex, String key, List<String> batchData, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.del(key);
            jedis.rpush(key, batchData.toArray(new String[batchData.size()]));
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    public static String popDataFromListJedis(Integer dbIndex, String key) throws Exception {
        String value = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                value = jedis.lpop(key);
                value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return value;
    }

    public static String popDataFromListJedis(Integer dbIndex, String key, Integer timeout) throws Exception {
        String value = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                List<String> values = jedis.blpop(timeout, key);
                if (CollectionUtils.isNotEmpty(values)
                        && values.size() > 1) {
                    value = values.get(1);
                    value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;
                }
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return value;
    }

    /**
     * 从列表中删除元素（批量）
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param values 批量数据
     */
    public static void deleteDataFromListJedis(Integer dbIndex, String key, List<String> values) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            Pipeline pipeline = jedis.pipelined();
            if (values != null && !values.isEmpty()) {
                for (String val : values) {
                    pipeline.lrem(key, 0, val);
                }
            }
            pipeline.sync();
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 将HushMap保存到Redis
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param map 映射表
     * @param cacheSeconds 缓存时间，0表示永久保存
     */
    public static void addHashMapToJedis(Integer dbIndex, String key, Map<String, String> map, int cacheSeconds) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        if (map != null && map.size() > 0) {
            try {
                jedis = getJedis();
                jedis.select(dbIndex);
                jedis.hmset(key, map);
                if (cacheSeconds != 0)
                    jedis.expire(key, cacheSeconds);
            } catch (Exception e) {
                isBroken = true;
                exc = e;
                e.printStackTrace();
            } finally {
                release(jedis, isBroken);
                if (exc != null) {
                    throw exc;
                }
            }
        }
    }

    /**
     * 向Redis中的HashMap添加字符串数据
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param field 属性
     * @param value 数据值
     * @param cacheSeconds 缓存时间，0表示永久保存
     */
    public static void addHashMapToJedis(Integer dbIndex, String key, String field, String value, int cacheSeconds) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.select(dbIndex);
                jedis.hset(key, field, value);
                if (cacheSeconds != 0) {
                    jedis.expire(key, cacheSeconds);
                }
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 更新Redis中的HashMap（增加存储在字段中存储由增量键哈希的数量）
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param incrementField 增量属性
     * @param incrementValue 增量加值
     * @param dataField 增加属性
     * @param dataValue 增加属性值
     */
    public static void updateHashMapToJedis(Integer dbIndex, String key, String incrementField,
                                            long incrementValue, String dataField, String dataValue) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.hincrBy(key, incrementField, incrementValue);
            jedis.hset(key, dataField, dataValue);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 从Redis中获取字符串
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return 数据值
     */
    public static String getStringFromJedis(Integer dbIndex, String key) throws Exception {
        String value = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                value = jedis.get(key);
                value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return value;
    }

    /**
     * 从Redis中批量获取字符串（获取顺序一致）
     *
     * @param dbIndex 数据库序号
     * @param keys 数据键
     * @return 数据值列表
     */
    public static List<String> getStringFromJedis(Integer dbIndex, String[] keys) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            return jedis.mget(keys);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return null;
    }

    /**
     * 从Redis中获取数据列表
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return 数据值列表
     */
    public static List<String> getListFromJedis(Integer dbIndex, String key) throws Exception {
        List<String> list = null;
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                list = jedis.lrange(key, 0, -1);
            }
        } catch (JedisException e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return list;
    }

    /**
     * 从Redis中获取数据列表
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return 数据值列表
     */
    public static List<String> getListFromJedis(Integer dbIndex, String key, Integer start, Integer end) throws Exception {
        List<String> list = null;
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                list = jedis.lrange(key, start, end);
            }
        } catch (JedisException e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return list;
    }

    /**
     * 从Redis中获取数据
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return 数据值列表
     */
    public static String getListFromJedis(Integer dbIndex, String key, Integer index) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        String value = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                List<String> values = jedis.lrange(key, index, index);
                if (null != values && values.size() > 0) {
                    value = values.get(0);
                }

            }
        } catch (JedisException e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return value;
    }

    /**
     * 从Redis中获取数据集合
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return 数据集合
     */
    public static Set<String> getSetFromJedis(Integer dbIndex, String key) throws Exception {
        Set<String> list = null;
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                list = jedis.smembers(key);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return list;
    }

    /**
     * 判断集合中是否包含value值
     *
     * @param dbIndex
     * @param key
     * @param value
     * @return
     * @throws Exception
     */
    public static Boolean isSetContainValueFromJedis(Integer dbIndex, String key, String value) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        Boolean isContainValue = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            if (jedis.exists(key)) {
                isContainValue = jedis.sismember(key, value);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return isContainValue;
    }

    /**
     * 从Redis中获取哈希表
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return 哈希表
     */
    public static Map<String, String> getHashMapFromJedis(Integer dbIndex, String key) throws Exception {
        Map<String, String> hashMap = null;
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            hashMap = jedis.hgetAll(key);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return hashMap;
    }

    /**
     * 从Redis中获取哈希表中某字段的值
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param field
     * @return
     */
    public static String getHashMapValueFromJedis(Integer dbIndex, String key, String field) throws Exception {
        String value = null;
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.select(dbIndex);
                if (jedis.exists(key)) {
                    value = jedis.hget(key, field);
                }
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return value;
    }

    /**
     * 从Redis中删除哈希表中某字段的值
     *
     * @param dbIndex
     * @param key
     * @param field
     * @throws Exception
     */
    public static void removeHashMapFromJedis(Integer dbIndex, String key, String field) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.select(dbIndex);
                if (jedis.exists(key)) {
                    jedis.hdel(key, field);
                }
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 向指定排序集合中添加数据
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param value 数据值
     * @param score 排序评分
     * @param cacheSeconds 缓存时间期限（秒）：0表示永久
     * @throws Exception
     */
    public static void addSortedSetToJedis(Integer dbIndex, String key, String value, Long score, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.zadd(key, score, value);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 向指定排序集合中添加数据
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param value 数据值
     * @param score 排序评分
     * @param cacheSeconds 缓存时间期限（秒）：0表示永久
     * @throws Exception
     */
    public static void addSortedSetToJedis(Integer dbIndex, String key, String value, Double score, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.zadd(key, score, value);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 获取排序集合已存数据量
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return
     * @throws Exception
     */
    public static Long getSortedSetSizeFromJedis(Integer dbIndex, String key) throws Exception {
        Long size = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            boolean existKey = jedis.exists(key);
            if (existKey) {
                size = jedis.zcard(key);
            } else {
                size = null;
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return size;
    }

    /**
     * Value是否包含在排序集合当中
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param value 数据值
     * @return
     * @throws Exception
     */
    public static Boolean isSortedSetContainValueFromJedis(Integer dbIndex, String key, String value) throws Exception {
        Boolean isContain = false;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            Long zrank = jedis.zrank(key, value);
            if (null != zrank) {
                isContain = true;
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return isContain;
    }

    /**
     * 获取排序集合中的成员
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param start 起始元素位置
     * @param end 终止元素位置   -1表示最后一个元素
     * @return
     * @throws Exception
     */
    public static Set<String> getSortedSetFromJedis(Integer dbIndex, String key, Long start, Long end) throws Exception {
        Set<String> zrange = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            zrange = jedis.zrange(key, start, end);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return zrange;
    }

    /**
     * 获取排序集合中的成员的分数
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param member 集合成员
     * @return
     * @throws Exception
     */
    public static Long getSortedSetScoreFromJedis(Integer dbIndex, String key, String member) throws Exception {
        Long score = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            Double scoreValue = jedis.zscore(key, member);
            if (null != scoreValue) {
                score = scoreValue.longValue();
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return score;
    }

    /**
     * 获取排序集合中的成员的分数
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param member 集合成员
     * @return
     * @throws Exception
     */
    public static Double getSortedSetDoubleScoreFromJedis(Integer dbIndex, String key, String member) throws Exception {
        Double score = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            score = jedis.zscore(key, member);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return score;
    }

    /**
     * 获取排序集合中的成员(通过Score)
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param start 起始元素Score
     * @param end 终止元素Score
     * @return
     * @throws Exception
     */
    public static Set<String> getSortedSetByScoreFromJedis(Integer dbIndex, String key, Long start, Long end) throws Exception {
        Set<String> zrange = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            zrange = jedis.zrangeByScore(key, start, end);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return zrange;
    }

    /**
     * 获取排序集合当中成员（通过Score 带分页）
     *
     * @param dbIndex
     * @param key
     * @param start
     * @param end
     * @param offset
     * @param count
     * @return
     * @throws Exception
     */
    public static List<TupleData> getSortedSetByScoreWithScoreFromJedis(Integer dbIndex, String key, Long start, Long end, Integer offset, Integer count) throws Exception {
        List<TupleData> zrange = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            Set<Tuple> tuples = jedis.zrangeByScoreWithScores(key, null == start ? "-inf" : String.valueOf(start), null == end ? "+inf" : String.valueOf(end), offset, count);
            if (CollectionUtils.isNotEmpty(tuples)) {
                zrange = new ArrayList<TupleData>();
                List<Tuple> tupleList = new ArrayList<Tuple>(tuples);
                for (Tuple tuple : tupleList) {
                    TupleData data = new TupleData();
                    data.setElement(tuple.getElement());
                    data.setScore(new Double(tuple.getScore()).longValue());
                    zrange.add(data);
                }
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return zrange;
    }

    /**
     * 获取排序集合中成员的排名（Score由低到高排序）
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param member 集合成员
     * @return
     * @throws Exception
     */
    public static Long getSortedSetMemberLowRankFromJedis(Integer dbIndex, String key, String member) throws Exception {
        Long rank = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            rank = jedis.zrank(key, member);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return rank;
    }

    /**
     * 获取排序集合中成员的排名（Score由高到低排序）
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @param member 集合成员
     * @return
     * @throws Exception
     */
    public static Long getSortedSetMemberHighRankFromJedis(Integer dbIndex, String key, String member) throws Exception {
        Long rank = null;
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            rank = jedis.zrevrank(key, member);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return rank;
    }

    /**
     * 移除SortedSet中指定成员
     *
     * @param dbIndex
     * @param key
     * @throws Exception
     */
    public static void removeSortedSetByMemberFromJedis(Integer dbIndex, String key, String member) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.zrem(key, member);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 移除SortedSet中指定分数
     *
     * @param dbIndex
     * @param key
     * @param score
     * @throws Exception
     */
    public static void removeSortedSetByScoreFromJedis(Integer dbIndex, String key, Long score) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.zremrangeByScore(key, Double.valueOf(score), Double.valueOf(score));
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 将 Redis中key 中储存的数字值增一
     *
     * @param dbIndex 数据库序号
     * @param identifyName 数据键
     * @return 增一之后的数值
     */
    public static Long getIdentifyId(Integer dbIndex, String identifyName) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        Long identify = null;
        Exception exc = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.select(dbIndex);
                identify = jedis.incr(identifyName);
                if (identify == 0) {
                    return jedis.incr(identifyName);
                } else {
                    return identify;
                }
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return null;
    }

    /**
     * 删除某db的某个key值
     *
     * @param key 数据键
     * @return
     */
    public static Long delKeyFromJedis(Integer dbIndex, String key) throws Exception {
        boolean isBroken = false;
        Jedis jedis = null;
        long result = 0;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            return jedis.del(key);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return result;
    }

    /**
     * 删除某db某些Key值
     *
     * @param dbIndex
     * @param keys
     * @return
     * @throws Exception
     */
    public static Long delKeyFromJedis(Integer dbIndex, List<String> keys) throws Exception {
        Long result = 0L;
        if (null != dbIndex
                && CollectionUtils.isNotEmpty(keys)) {
            Jedis jedis = null;
            boolean isBroken = false;
            Exception exc = null;
            try {
                jedis = getJedis();
                jedis.select(dbIndex);
                result = jedis.del(keys.toArray(new String[] {}));
            } catch (Exception e) {
                isBroken = true;
                exc = e;
            } finally {
                release(jedis, isBroken);
                if (exc != null) {
                    throw exc;
                }
            }
        }
        return result;
    }

    /**
     * 根据dbIndex flushDB每个shard
     *
     * @param dbIndex 数据库序号
     */
    public static void flushDBFromJedis(int dbIndex) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.flushDB();
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 是否存在值
     *
     * @param dbIndex 数据库序号
     * @param key 数据键
     * @return
     */
    public static boolean existKey(Integer dbIndex, String key) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        boolean isExist = false;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            isExist = jedis.exists(key);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return isExist;
    }

    public static final void expireKey(Integer dbIndex, String key, int cacheSeconds) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.expire(key, cacheSeconds);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 消息队列发布消息
     *
     * @param channel
     * @param message
     * @throws Exception
     */
    public static void publish(String channel, String message) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.publish(channel, message);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 订阅消息队列
     *
     * @param jedisPubSub
     * @param channels
     * @throws Exception
     */
    public static void subscribe(JedisPubSub jedisPubSub, String... channels) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.subscribe(jedisPubSub, channels);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 创建事务
     *
     * @return
     * @throws Exception
     */
    public static Transaction transaction(Integer dbIndex) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        Transaction transaction = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            transaction = jedis.multi();
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            if (exc != null) {
                release(jedis, isBroken);
                throw exc;
            }
        }
        return transaction;
    }

    /**
     * 执行事务
     *
     * @param transaction
     * @return
     * @throws Exception
     */
    public static List<Object> transactionExec(Transaction transaction) throws Exception {
        List<Object> results = new ArrayList<Object>();
        if (null != transaction) {
            try {
                results = transaction.exec();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return results;
    }

    /**
     * 设置监视指定Key
     *
     * @param dbIndex
     * @param key
     * @throws Exception
     */
    public static void transactionWatch(Integer dbIndex, String key) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.watch(key);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 设置监视指定Key
     *
     * @param dbIndex
     * @param key
     * @throws Exception
     */
    public static void transactionUnWatch(Integer dbIndex, String key) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            jedis.unwatch();
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
    }

    /**
     * 获取Jedis
     * @throws Exception
     */
    public static Jedis createJedis() throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        try {
            jedis = getJedis();
        } catch (Exception e) {
            isBroken = true;
            release(jedis, isBroken);
        }
        return jedis;
    }

    /**
     * 释放Jedis
     *
     * @return
     * @throws Exception
     */
    public static void releaseJedis(Jedis jedis, Boolean isBroken) throws Exception {
        if (null != jedis) {
            release(jedis, isBroken);
        }
    }

    public static final List<String> getKeys(Integer dbIndex, String pattern) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        Set<String> keys = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            keys = jedis.keys(pattern);
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        if (keys != null && keys.size() > 0) {
            return new ArrayList<String>(keys);
        } else {
            return new ArrayList<String>();
        }
    }

    /**
     * 尝试获取分布式锁
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Integer dbIndex, String lockKey, String requestId, int expireTime) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            String result = jedis.set(lockKey, requestId, NOT_EXIST, SECONDS, expireTime);
            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return false;
    }

    /**
     * 释放分布式锁
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Integer dbIndex, String lockKey, String requestId) throws Exception {
        Jedis jedis = null;
        boolean isBroken = false;
        Exception exc = null;
        try {
            jedis = getJedis();
            jedis.select(dbIndex);
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
        } catch (Exception e) {
            isBroken = true;
            exc = e;
        } finally {
            release(jedis, isBroken);
            if (exc != null) {
                throw exc;
            }
        }
        return false;
    }

    /* Setter&Getter Method */
    @Autowired
    public static void setJedisPool(JedisPool pool) {
        jedisPool = pool;
    }
    public String getAuthentication() {
        return authentication;
    }
    public void setAuthentication(String authentication) {
        RedisUtils.authentication = authentication;
    }

    /* Class */
    public static final class TupleData {
        private String element;
        private Long score;

        public String getElement() {
            return element;
        }
        public void setElement(String element) {
            this.element = element;
        }
        public Long getScore() {
            return score;
        }
        public void setScore(Long score) {
            this.score = score;
        }
    }
}
